'use strict'

const path = require('path')
const fse = require('fs-extra')
const npminstall = require('npminstall')
const pkgDir = require('pkg-dir')
const pathExists = require('path-exists')
const { isObject } = require('@imooc-yishen-cli-dev/utils')
const formatPath = require('@imooc-yishen-cli-dev/format-path')
const {
  getDefaultRegistry,
  getNpmLatestVersion,
} = require('@imooc-yishen-cli-dev/get-npm-info')

class Package {
  constructor(options) {
    if (!options) {
      throw new Error('Package 类的 options 参数不能为空')
    }
    if (!isObject(options)) {
      throw new Error('Package 类的 options 参数必须为对象')
    }
    this.targetPath = options.targetPath
    this.storeDir = options.storeDir
    this.packageName = options.packageName
    this.packageVersion = options.packageVersion
    this.cacheFilePathPrefix = this.packageName?.replaceAll('/', '_')
  }

  async prepare() {
    if (this.storeDir && !pathExists(this.storeDir)) {
      fse.mkdirpSync(this.storeDir)
    }
    if (this.packageVersion === 'latest') {
      this.packageVersion = await getNpmLatestVersion(this.packageName)
    }
  }

  get cacheFilePath() {
    return path.resolve(
      this.storeDir,
      `_${this.cacheFilePathPrefix}@${this.packageVersion}@${this.packageName}`
    )
  }

  getSpecificCacheFilePath(packageVersion) {
    return path.resolve(
      this.storeDir,
      `_${this.cacheFilePathPrefix}@${packageVersion}@${this.packageName}`
    )
  }

  // whether the local file exists
  async exists() {
    if (this.storeDir) {
      await this.prepare()
      return pathExists(this.cacheFilePath)
    } else {
      return pathExists.sync(this.targetPath)
    }
  }

  // install package
  async install() {
    await this.prepare()
    return npminstall({
      root: this.targetPath,
      storeDir: this.storeDir,
      registry: getDefaultRegistry(),
      pkgs: [
        {
          name: this.packageName,
          version: this.packageVersion,
        },
      ],
    })
  }

  // update package
  async update() {
    this.prepare()
    // 1.获取最新的npm模块版本号
    const newestPackageVersion = await getNpmLatestVersion(this.packageName)
    // 2.查询最新版本号对应的路径是否存在
    if (!pathExists.sync(this.getSpecificCacheFilePath(newestPackageVersion))) {
      // 3.如果不存在，则直接安装最新版本
      await npminstall({
        root: this.targetPath,
        storeDir: this.storeDir,
        registry: getDefaultRegistry(),
        pkgs: [
          {
            name: this.packageName,
            version: newestPackageVersion,
          },
        ],
      })
      this.packageVersion = newestPackageVersion
    }
    return null
  }

  // get entry file path
  getRootFilePath() {
    function _getRootFile(targetPath) {
      // 获取package.json 所在目录
      const dir = pkgDir.sync(targetPath)
      if (dir) {
        // 读取 package.json
        const pkg = require(path.join(dir, 'package.json'))
        // mian/lib - path
        return formatPath(path.join(dir, pkg.main))
      }
      return null
    }
    if (this.storeDir) {
      // 缓存模式
      return _getRootFile(this.cacheFilePath)
    } else {
      return _getRootFile(this.targetPath)
    }
  }
}

module.exports = Package
